/*
 * Copyright (c) 2007 jNetX.
 * http://www.jnetx.com
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of
 * jNetX. You shall not disclose such Confidential Information and
 * shall use it only in accordance with the terms of the license
 * agreement you entered into with jNetX.
 *
 * $Id$
 */
package com.jnetx.javax.sip.header;

import com.jnetx.javax.sip.util.Parametrized;

import javax.sip.address.URI;
import javax.sip.header.ProxyAuthenticateHeader;
import javax.sip.header.Header;
import java.text.ParseException;

/**
 * A Proxy-Authenticate header field value contains an authentication
 * challenge. When a UAC sends a request to a proxy server, the proxy server
 * MAY authenticate the originator before the request is processed. If no
 * credentials (in the Proxy-Authorization header field) are provided in the
 * request, the proxy can challenge the originator to provide credentials by
 * rejecting the request with a 407 (Proxy Authentication Required) status
 * code.  The proxy MUST populate the 407 (Proxy Authentication Required)
 * message with a Proxy-Authenticate header field value applicable to the
 * proxy for the requested resource.  The field value consists of a challenge
 * that indicates the authentication and parameters applicable to the proxy
 * for this RequestURI.
 * <p/>
 * Note - Unlike its usage within HTTP, the ProxyAuthenticateHeader must be
 * passed upstream in the Response to the UAC. In SIP, only UAC's can
 * authenticate themselves to proxies.
 * <p/>
 * Proxies MUST NOT add values to the Proxy-Authorization header field. All
 * 407 (Proxy Authentication Required) responses MUST be forwarded upstream
 * toward the UAC following the procedures for any other response. It is the
 * UAC's responsibility to add the Proxy-Authorization header field value
 * containing credentials for the realm of the proxy that has asked for
 * authentication.
 * <p/>
 * When the originating UAC receives the 407 (Proxy Authentication Required)
 * it SHOULD, if it is able, re-originate the request with the proper
 * credentials. It should follow the same procedures for the display of the
 * "realm" parameter that are given above for responding to 401. If no
 * credentials for a realm can be located, UACs MAY attempt to retry the
 * request with a username of "anonymous" and no password (a password of "").
 * The UAC SHOULD also cache the credentials used in the re-originated request.
 * <p/>
 * For Example:<br>
 * <code>Proxy-Authenticate: Digest realm="jcp.org",
 * domain="sip:ss1.duke.com", qop="auth",
 * nonce="f84f1cec41e6cbe5aea9c8e88d359", opaque="", stale=FALSE,
 * algorithm=MD5</code>
 *
 * @author <a href="mailto:dparhonin@jnetx.ru">Dmitry Parhonin</a>
 * @version $Revision$
 * @see javax.sip.header.Parameters
 * @see javax.sip.header.ProxyAuthorizationHeader
 */
public class ProxyAuthenticateHeaderImpl extends ParametrizedHeaderBase implements ProxyAuthenticateHeader {
    private String scheme;

    private static final ProxyAuthenticateHeaderParser parser = new ProxyAuthenticateHeaderParser();

    public ProxyAuthenticateHeaderImpl() {
        super(ProxyAuthenticateHeader.NAME);
    }

    ProxyAuthenticateHeaderImpl(byte[] data, int start, int end) {
        super(ProxyAuthenticateHeader.NAME, data, start, end);
    }

    public Object clone() {
        final ProxyAuthenticateHeaderImpl header = new ProxyAuthenticateHeaderImpl();
        header.cloneBase(this);
        if (parsed) {
            header.cloneParameters(this);
            header.scheme = this.scheme;
        }
        return header;
    }

    protected HeaderParser getParser() {
        return parser;
    }

    @Override
    protected Parametrized<Header> createParametrized() {
        return new Parametrized<Header>(this, Parametrized.QuotationType.DOUBLE);
    }
    protected String getValueAsString() {
        return scheme;
    }

    @Override
    protected StringBuilder getParametersAsString(StringBuilder sb, char delimiter) {
        final String params = parametrized.getParametersAsString(',');
        if (params != null && !params.equals(""))
            sb.append(' ').append(params);
        return sb;
    }

    /**
     * Sets the scheme of the challenge information for this WWWAuthenticateHeader.
     * For example, Digest.
     *
     * @param scheme the new string value that identifies the challenge
     *               information scheme.
     */
    public void setScheme(String scheme) {
        parse();
        this.scheme = scheme;
        invalidateHeaderData();
    }

    /**
     * Returns the scheme of the challenge information for this WWWAuthenticateHeader.
     *
     * @return the string value of the challenge information.
     */
    public String getScheme() {
        parse();
        return this.scheme;
    }

    /**
     * Sets the Realm of the WWWAuthenicateHeader to the realm
     * parameter value. Realm strings MUST be globally unique.  It is
     * RECOMMENDED that a realm string contain a hostname or domain name.
     * Realm strings SHOULD present a human-readable identifier that can be
     * rendered to a user.
     *
     * @param realm the new Realm String of this WWWAuthenicateHeader.
     * @throws java.text.ParseException which signals that an error has been reached
     *                                  unexpectedly while parsing the realm.
     */
    public void setRealm(String realm) throws ParseException {
        setParameter("realm", realm);
    }

    /**
     * Returns the Realm value of this WWWAuthenicateHeader. This convenience
     * method returns only the realm of the complete Challenge.
     *
     * @return the String representing the Realm information, null if value is
     *         not set.
     */
    public String getRealm() {
        return getParameter("realm");
    }

    /**
     * Sets the Nonce of the WWWAuthenicateHeader to the nonce
     * parameter value.
     *
     * @param nonce the new nonce String of this WWWAuthenicateHeader.
     * @throws java.text.ParseException which signals that an error has been reached
     *                                  unexpectedly while parsing the nonce value.
     */
    public void setNonce(String nonce) throws ParseException {
        setParameter("nonce", nonce);
    }

    /**
     * Returns the Nonce value of this WWWAuthenicateHeader.
     *
     * @return the String representing the nonce information, null if value is
     *         not set.
     */
    public String getNonce() {
        return getParameter("nonce");
    }

    /**
     * Sets the URI of the WWWAuthenicateHeader to the URI parameter value.
     *
     * @param uri the new URI of this WWWAuthenicateHeader.
     * @deprecated
     */
    public void setURI(URI uri) {
    }

    /**
     * Returns the URI value of this WWWAuthenicateHeader, for example DigestURI.
     *
     * @return the URI representing the URI information, null if value is
     *         not set.
     * @deprecated
     */
    public URI getURI() {
        return null;
    }

    /**
     * Sets the Algorithm of the WWWAuthenicateHeader to the new
     * algorithm parameter value.
     *
     * @param algorithm the new algorithm String of this WWWAuthenicateHeader.
     * @throws java.text.ParseException which signals that an error has been reached
     *                                  unexpectedly while parsing the algorithm value.
     */
    public void setAlgorithm(String algorithm) throws ParseException {
        setParameter("algorithm", algorithm, Parametrized.QuotationType.NONE);
    }

    /**
     * Returns the Algorithm value of this WWWAuthenicateHeader.
     *
     * @return the String representing the Algorithm information, null if the
     *         value is not set.
     */
    public String getAlgorithm() {
        return getParameter("algorithm");
    }

    /**
     * Sets the Qop value of the WWWAuthenicateHeader to the new
     * qop parameter value.
     *
     * @param qop the new Qop string of this WWWAuthenicateHeader.
     * @throws java.text.ParseException which signals that an error has been reached
     *                                  unexpectedly while parsing the Qop value.
     */
    public void setQop(String qop) throws ParseException {
        setParameter("qop", qop, Parametrized.QuotationType.NONE);
    }

    /**
     * Returns the Qop value of this WWWAuthenicateHeader.
     *
     * @return the string representing the Qop information, null if the
     *         value is not set.
     */
    public String getQop() {
        return getParameter("qop");
    }

    /**
     * Sets the Opaque value of the WWWAuthenicateHeader to the new
     * opaque parameter value.
     *
     * @param opaque the new Opaque string of this WWWAuthenicateHeader.
     * @throws java.text.ParseException which signals that an error has been reached
     *                                  unexpectedly while parsing the opaque value.
     */
    public void setOpaque(String opaque) throws ParseException {
        setParameter("opaque", opaque);
    }

    /**
     * Returns the Opaque value of this WWWAuthenicateHeader.
     *
     * @return the String representing the Opaque information, null if the
     *         value is not set.
     */
    public String getOpaque() {
        return getParameter("opaque");
    }

    /**
     * Sets the Domain of the WWWAuthenicateHeader to the domain
     * parameter value.
     *
     * @param domain the new Domain string of this WWWAuthenicateHeader.
     * @throws java.text.ParseException which signals that an error has been reached
     *                                  unexpectedly while parsing the domain.
     */
    public void setDomain(String domain) throws ParseException {
        setParameter("domain", domain);
    }

    /**
     * Returns the Domain value of this WWWAuthenicateHeader.
     *
     * @return the String representing the Domain information, null if value is
     *         not set.
     */
    public String getDomain() {
        return getParameter("domain");
    }

    /**
     * Sets the value of the stale parameter of the WWWAuthenicateHeader to the
     * stale parameter value.
     *
     * @param stale the new boolean value of the stale parameter.
     */
    public void setStale(boolean stale) {
        try {
            setParameter("stale", Boolean.toString(stale));
        } catch (ParseException e) {
        }
    }

    /**
     * Returns the boolean value of the state paramater of this
     * WWWAuthenicateHeader.
     *
     * @return the boolean representing if the challenge is stale.
     */
    public boolean isStale() {
        final String isStale = getParameter("stale");
        return isStale != null && isStale.equalsIgnoreCase("true");
    }
}
/*
 * $Log$
 */